﻿using System;
using System.Collections.Generic;
using System.Linq;
using Beaker.Collections;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Beaker.Common.Specs.Collections
{
	[TestClass]
	public class EnumerableExtensionSpecs
	{
		[TestMethod]
		public void AlteringSourceDataShouldNotInfluentCreateReadOnlyList()
		{
			// arrange
			var array = new[] { "Foo", "Bar" };

			// act
			IReadOnlyList<string> readOnlyList = EnumerableExtensions.ToReadOnlyList(array);
			array[1] = "raB";

			// assert
			readOnlyList
				.Should().BeEquivalentTo(new string[] { "Foo", "Bar" }, because: "the read only list should not be modified");
		}

		[TestMethod]
		public void AlteringTheReadOnlyListShouldNotBePossible()
		{
			// arrange
			var array = new[] { "Foo", "Bar" };

			// act
			var readOnlyList = (IList<string>)EnumerableExtensions.ToReadOnlyList(array);
			Action act = () => readOnlyList[1] = "raB";

			// assert
			act.ShouldThrow<NotSupportedException>(because: "altering a read only list is not supported");
		}

		[TestMethod]
		public void UsingDoAllItemsShouldBeProcessed()
		{
			var array = new[] { "Foo", "Bar" };
			var processedItems = new List<string>();

			EnumerableExtensions.Do(array, processedItems.Add);

			processedItems.Should().BeEquivalentTo(array);
		}

		[TestMethod]
		public void UsingDoDefferedAllItemsShouldBeProcessed()
		{
			var array = new[] { "Foo", "Bar" };
			var processedItems = new List<string>();

			EnumerableExtensions.DoDeferred(array, processedItems.Add)
				.ToList(); // execute deferred do

			processedItems.Should().BeEquivalentTo(array, because: "all items should be processed");
		}

		[TestMethod]
		public void UsingDoDefferedTakingOnlyFirstThenOnlyFirstShouldBeProcessed()
		{
			var array = new[] { "Foo", "Bar" };
			var processedItems = new List<string>();

			EnumerableExtensions.DoDeferred(array, processedItems.Add)
				.First(); // execute deferred do, but only first

			processedItems.Should().BeEquivalentTo(new[] { "Foo" }, because: "only first item was taken from deferred sequence");
		}

		[TestMethod]
		public void UsingDoDefferedAllItemsShouldBeChainedToNextOperator()
		{
			var array = new[] { "Foo", "Bar" };

			List<string> output = EnumerableExtensions.DoDeferred(array, s => { })
				.ToList(); // execute deferred do

			output.Should().BeEquivalentTo(array, because: "all items should be passed to next operator");
		}
	}
}
